package com.jack.network;

import com.jack.network.annotation.Network;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author: dingfeng
 * @date: 2020-04-15
 * @since: 1.0.0
 **/
public class NetWorkMonitorImpl implements INetWorkMonitor {

    private Map<Object, List<MethodManager>> mNetObservers;

    public NetWorkMonitorImpl() {
        this.mNetObservers = new HashMap<>();
    }

    @Override
    public void registerObserver(Object register) {
        List<MethodManager> methods = mNetObservers.get(register);
        if (methods == null) {
            methods = findAnnotationMethods(register);
            mNetObservers.put(register, methods);
        }
    }

    private List<MethodManager> findAnnotationMethods(Object register) {
        List<MethodManager> methodList = new ArrayList<>();

        Class<?> clazz = register.getClass();

        Method[] methods = clazz.getMethods();

        for (Method method : methods) {
            Network network = method.getAnnotation(Network.class);
            if (network == null) {
                continue;
            }
            Type returnType = method.getGenericReturnType();
            if (!"void".equalsIgnoreCase(returnType.toString())) {
                throw new RuntimeException(method.getName() + "方法返回必须是 void");
            }

            Class<?>[] parameterTypes = method.getParameterTypes();
            if (parameterTypes.length != 1) {
                throw new RuntimeException(method.getName() + "方法有且只有一个参数");
            }

            methodList.add(new MethodManager(parameterTypes[0], network.netType(), method));
        }

        return methodList;
    }

    @Override
    public void unRegisterObserver(Object register) {
        if (!mNetObservers.isEmpty())
            mNetObservers.remove(register);
    }

    @Override
    public void unRegisterAllObservers() {
        if (!mNetObservers.isEmpty())
            mNetObservers.clear();
        mNetObservers = null;
    }

    @Override
    public void notifyNetwork(NetWorkType netType) {
        Set<Object> set = mNetObservers.keySet();

        for (final Object getter : set) {

            List<MethodManager> methodList = mNetObservers.get(getter);

            if (methodList != null) {

                for (final MethodManager method : methodList) {

                    if (method.getType().isAssignableFrom(netType.getClass())) {

                        final NetWorkType type = method.getNetType();

                        if (type == NetWorkType.WIFI) {
                            if (netType == NetWorkType.WIFI || netType == NetWorkType.NONE) {
                                invoke(method, getter, netType);
                            }
                        } else if (type == NetWorkType.MOBILE) {
                            if (netType == NetWorkType.MOBILE || netType == NetWorkType.NONE) {
                                invoke(method, getter, netType);
                            }
                        } else if (type == NetWorkType.NONE) {
                            if (netType == NetWorkType.NONE) {
                                invoke(method, getter, netType);
                            }
                        }
                    }
                }
            }
        }
    }

    private void invoke(MethodManager method, Object getter, NetWorkType netType) {
        Method execute = method.getMethod();
        try {
            execute.invoke(getter, netType);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

}
